#include <buola/chart/mappings/clinearmapping.h>

namespace buola { namespace chart {

CLinearMapping::CLinearMapping()
{
    mMinSrc=0;
    mMaxSrc=1;
}

CLinearMapping::~CLinearMapping()
{
}

double CLinearMapping::Map(double pV)
{
    return mMinDest+(pV-mMinSrc)*mMult;
}

double CLinearMapping::InverseMap(double pV)
{
    return mMinSrc+(pV-mMinDest)/mMult;
}

int CLinearMapping::GetTicks(std::vector<double> &pTicks,double pMinDist)
{
    int lMaxTicks=abs((int)floor((mMaxDest-mMinDest)/pMinDist));
    double lMinTickStep=(mMaxSrc-mMinSrc)/lMaxTicks;
    double lMagnitudeOrder=pow(10,floor(log10(lMinTickStep)));
    
    double lStep;
    if(2*lMagnitudeOrder>lMinTickStep)
        lStep=2*lMagnitudeOrder;
    else if(5*lMagnitudeOrder>lMinTickStep)
        lStep=5*lMagnitudeOrder;
    else
        lStep=10*lMagnitudeOrder;
        
    pTicks.clear();
    double lFirst=lStep*ceil(mMinSrc/lStep);
    
    for(double lPos=lFirst;lPos<mMaxSrc;lPos+=lStep)
        pTicks.push_back(lPos);

    int lExp=(int)floor(log10(lStep));  

    if(lExp>=-2&&lExp<=2) lExp=0;

    return lExp;
}

void CLinearMapping::AutoScale(double pMin,double pMinPos,double pMax,
                                    bool pNiceLimits,double pMinDist)
{
    mMinSrc=pMin;
    mMaxSrc=pMax;

    if(pNiceLimits)
    {
        int lMaxTicks=abs((int)floor((mMaxDest-mMinDest)/pMinDist));
        double lMinTickStep=(mMaxSrc-mMinSrc)/lMaxTicks;
        double lMagnitudeOrder=pow(10,floor(log10(lMinTickStep)));
    
        double lStep;
        if(2*lMagnitudeOrder>lMinTickStep)
            lStep=2*lMagnitudeOrder;
        else if(5*lMagnitudeOrder>lMinTickStep)
            lStep=5*lMagnitudeOrder;
        else
            lStep=10*lMagnitudeOrder;
        
        mMinSrc=floor(mMinSrc/lStep)*lStep;
        mMaxSrc=ceil(mMaxSrc/lStep)*lStep;
    }

    Update();
}

void CLinearMapping::Update()
{
    mMult=(mMaxDest-mMinDest)/(mMaxSrc-mMinSrc);
}

/*namespace chart*/ } /*namespace buola*/ }
